package zcache

import (
	"sync"
	"time"
)

type TimeoutCache func(k, v interface{})

type cacheObject struct {
	obj       interface{}
	unix      int64
	outTime   int64
	onTimeout TimeoutCache
}

type Cache struct {
	cMap      sync.Map
	onTimeout TimeoutCache
}

func New() (c *Cache) {
	c = &Cache{}
	c.checkOutTime()
	return c
}

func (c *Cache) SetTimeoutEvent(f TimeoutCache) {
	c.onTimeout = f
}

func (c *Cache) Put(k, v interface{}, outTime ...int64) {
	obj := cacheObject{obj: v, unix: time.Now().Unix()}
	if len(outTime) > 0 {
		obj.outTime = outTime[0]
	}
	c.cMap.Store(k, obj)
	return
}

func (c *Cache) Get(k interface{}) interface{} {
	v, ok := c.cMap.Load(k)
	if ok {
		return v.(cacheObject).obj
	}
	return nil
}

func (c *Cache) Del(k interface{}) {
	c.cMap.Delete(k)
}

func (c *Cache) checkOutTime() {
	var interval = int64(100 * time.Millisecond)
	go func() {
		for {
			c.cMap.Range(func(k, v interface{}) bool {
				ex := v.(cacheObject).unix
				if v.(cacheObject).outTime > 0 && time.Now().Unix()-ex > v.(cacheObject).outTime {
					if c.onTimeout != nil {
						c.onTimeout(k, v)
					}
					c.cMap.Delete(k)
				}
				return true
			})
			time.Sleep(time.Duration(interval) * time.Millisecond)
		}
	}()
}
